﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Threading;
using DM4Script;
using sscore;
using sscore.Requests;
using sscore.Utils;

namespace DM4
{
    public class ModuleBase : IModule
    {
        static public object Locker = new object();
        static public object ErrLocker = new object();
        //static public object LogLocker = new object();
        static public object TestLocker = new object();

        protected string Version = "1.0";

        public DataTable DtHelp;

        protected string RootUrl;
        /// <summary>
        /// ModuleName Example: "Sex Offenders - [AR]"	string
        /// </summary>
        protected string Description = "Base DM4 module class";

        protected int UsrId;

        /// <summary>
        /// ModuleCode Example: "SO_AR"	string
        /// </summary>
        protected string ModuleCode = "MOD_BASE";

        /// <summary>
        /// WorkDir Example:
        /// </summary>
        protected string WorkDir;

        /// <summary>
        /// SettingsDir Example: "P:\IGOR\DM4\bin\Offenders\settings\SO_AR"
        /// </summary>
        protected string SettingsDir;

        protected string GroupSettingsDir;

        /// <summary>
        /// ResultDir Example: ""	
        /// </summary>
        protected string ResultDir;

        protected bool Test;

        protected CancellationToken Ct;

        protected ResultFile ResultFile;
        //protected Log Log;

        protected RegExp Re;

        protected Dictionary<string, string> Help;

        protected int StartParam;
        protected int StopParam;
        protected int MaxCount;

        protected DmTaskParams TaskParams;

        protected IDM4Core Core;

        //load session params, if it exists
        protected DBParams Params;

        protected DateTime StartTime;
        protected Int64 PrevWorkTime;

        protected RequestParams Rpm = new RequestParams(EncodingType.Utf8);

        protected RegExpEx RegExpr = new RegExpEx();
        
        protected int ResultCode = DM4Consts.SessionResultCodeNull;
        protected string ResultMessage = DM4Consts.SessionResultMessageNull;

        public List<Prototypes.Log.Point> GetSessions(int sessionsCount)
        {
            List<Prototypes.Log.Point> p = new List<Prototypes.Log.Point>();

            int count = sessionsCount < (StopParam - StartParam) ? sessionsCount : (StopParam - StartParam);
            int countPerSession = (StopParam - StartParam) / count;

            int z = 0;
            for (int i = StartParam; i < StopParam; i += countPerSession)
            {
                if (z < count - 1)
                {
                    p.Add(new Prototypes.Log.Point(i, i + countPerSession - 1));

                }
                else
                {
                    p.Add(new Prototypes.Log.Point(i, StopParam));
                    break;
                }
                z++;
            }

            return p;
        }

        public object GetModule()
        {
            return new ModuleBase();
        }

        public string GetModuleCode()
        {
            return ModuleCode;
        }

        public virtual bool IsOnCompleteModule()
        {
            return false;
        }

        public string GetInfo(string parameter)
        {
            if (parameter.ToUpper().Trim() == DmConsts.Description.ToUpper())
                return Description;

            if (parameter.ToUpper().Trim() == DmConsts.ModuleCode.ToUpper())
                return ModuleCode;

            if (parameter.ToUpper().Trim() == DmConsts.Version.ToUpper())
                return Version;

            return parameter.ToUpper().Trim() == DmConsts.Link.ToUpper() ? RootUrl : "";
        }

        public XMLInfo GetHelp()
        {
            if (DtHelp == null)
            {
                DtHelp = new DataTable { TableName = "dtModuleParamsHelp" };

                DtHelp.Columns.Add("Name", typeof(String));
                DtHelp.Columns.Add("Value", typeof(String));
                DtHelp.Columns.Add("Description", typeof(String));
            }

            return (new XMLInfo()).Load(DtHelp);
        }

        public virtual OperationResult Init(IDM4Core iCore, DmTaskParams param)
        {
            OperationResult or = new OperationResult { Result = DM4Consts.Ok };
            try
            {
                Core = iCore;
                UsrId = param.UsrId;

                TaskParams = param;
                Rpm.SessionName = TaskParams.SessionId;
                Ct = TaskParams.Ct;
                SysUtils.InitTraffic(TaskParams.PrevTraffic, TaskParams.SessionId);

                WorkDir = Core.GetModuleWorkDir(TaskParams.SessionId, ModuleCode);

                InitBase();
            }
            catch (Exception ex)
            {
                or.Message = ex.Message;
            }

            return or;
        }

        public virtual OperationResult Start()
        {
            DoWork();
            return new OperationResult();
        }

        public virtual OperationResult Stop()
        {
            throw new NotImplementedException();
        }

        public virtual OperationResult DoWork()
        {
            throw new NotImplementedException();
        }

        public void AddToHelp(string name, string value, string description)
        {
            if (DtHelp == null)
            {
                DtHelp = new DataTable { TableName = "dtModuleParamsHelp" };

                DtHelp.Columns.Add("Name", typeof(String));
                DtHelp.Columns.Add("Value", typeof(String));
                DtHelp.Columns.Add("Description", typeof(String));
            }

            DataRow dr = DtHelp.NewRow();
            dr["Name"] = name.Trim();
            dr["Value"] = value.Trim();
            dr["Description"] = description.Trim();

            DtHelp.Rows.Add(dr);
        }

        public void AddToHelp(string name, string value)
        {
            AddToHelp(name, value, "");
        }

        public virtual void InitBase()
        {
            StartTime = DateTime.Now;

            SettingsDir = String.Format("{0}\\{1}\\{2}", WorkDir, DmConsts.SettingsDir, ModuleCode);
            ResultDir = String.Format("{0}\\{1}\\{2}", WorkDir, DmConsts.ResultDir, ModuleCode);
            GroupSettingsDir = String.Format("{0}\\{1}\\{2}\\_GROUP", WorkDir, DmConsts.SettingsDir, ModuleCode);

            //create log file
            //try
            //{
            //    Log = Log.CreateLogWithoutDataset(String.Format("{0}\\{1}\\{2}.{3}", WorkDir, DmConsts.LogDir, TaskParams.SessionId, DmConsts.LogFilesExtension),
            //                                      EncodingType.Windows1251, LogMode.Full, false);
            //}
            //catch (Exception ex)
            //{
            //    WriteErrorLog(ex.Message);
            //    return;
            //}

            //initialize Reg Expression library component
            Re = new RegExp(String.Format("{0}\\{1}", SettingsDir, DmConsts.RegExpFileName));

            Params = new DBParams(Core.GetSysParam(DM4Consts.ConnectionString), DM4Consts.ParamsTableName, TaskParams.SessionId);
            //init parameters
            foreach (KeyValuePair<string, ParamEntry> key in TaskParams.SessionParams)
            {
                if (key.Value.Type == ParamType.String)
                {
                    Params.CreateStringParam(key.Key, (string)key.Value.GetValue());
                }
                else
                    if (key.Value.Type == ParamType.Integer)
                    {
                        Params.CreateIntegerParam(key.Key, (int)key.Value.GetValue());
                    }
                    else
                        if (key.Value.Type == ParamType.Boolean)
                            Params.CreateBooleanParam(key.Key, (bool)key.Value.GetValue());
            }

            //init test parameter
            if (!Params.Exists(DmConsts.TestParam)) Params.CreateBooleanParam(DmConsts.TestParam, false);
            Test = Params.GetBooleanParam(DmConsts.TestParam);
        }

        public void UpdateStatus(string status = DM4Consts.SessionRun)
        {
            if (TaskParams.UpdateSessionDelegate != null)
                lock (Locker)
                    TaskParams.UpdateSessionDelegate(TaskParams.SessionId, 0, 0, 0, status, true, false, false, false, SysUtils.GetTraffic(Rpm.SessionName), (StartTime - DateTime.Now).Ticks + PrevWorkTime, ResultCode, ResultMessage);
        }

        public void UpdateStatus(string status = DM4Consts.SessionRun, int resultCode = DM4Consts.SessionResultCodeNull, string resultMessage = DM4Consts.SessionResultMessageNull)
        {
            if (TaskParams.UpdateSessionDelegate != null)
                lock (Locker)
                    TaskParams.UpdateSessionDelegate(TaskParams.SessionId, 0, 0, 0, status, true, false, false, false, SysUtils.GetTraffic(Rpm.SessionName), (StartTime - DateTime.Now).Ticks + PrevWorkTime, resultCode, resultMessage);
        }

        public void UpdateErrors(int errorCountForAdd)
        {
            if (TaskParams.UpdateSessionDelegate != null)
                lock (Locker)
                    TaskParams.UpdateSessionDelegate(TaskParams.SessionId, 0, errorCountForAdd, 0, DM4Consts.SessionRun, false, false, false, true, SysUtils.GetTraffic(Rpm.SessionName), (StartTime - DateTime.Now).Ticks + PrevWorkTime);
        }

        public void UpdateProgress(double progress)
        {
            if (TaskParams.UpdateSessionDelegate != null)
                lock (Locker)
                    TaskParams.UpdateSessionDelegate(TaskParams.SessionId, 0, 0, progress, DM4Consts.SessionRun, false, false, true, false, SysUtils.GetTraffic(Rpm.SessionName), (StartTime - DateTime.Now).Ticks + PrevWorkTime);
        }

        public void UpdateSession(Int64 records, Int64 errors, double progress, string status = DM4Consts.SessionRun)
        {
            if (TaskParams.UpdateSessionDelegate != null)
                lock (Locker)
                    TaskParams.UpdateSessionDelegate(TaskParams.SessionId, records, errors, progress, status, true, true, true, true, SysUtils.GetTraffic(Rpm.SessionName), (StartTime - DateTime.Now).Ticks + PrevWorkTime, DM4Consts.SessionResultCodeNull, DM4Consts.SessionResultMessageNull);
        }

        public void UpdateSession(Int64 records, Int64 errors, double progress, string status = DM4Consts.SessionRun, int resultCode = DM4Consts.SessionResultCodeNull, string resultMessage = DM4Consts.SessionResultMessageNull)
        {
            if (TaskParams.UpdateSessionDelegate != null)
                lock (Locker)
                    TaskParams.UpdateSessionDelegate(TaskParams.SessionId, records, errors, progress, status, true, true, true, true, SysUtils.GetTraffic(Rpm.SessionName), (StartTime - DateTime.Now).Ticks + PrevWorkTime, resultCode, resultMessage);
        }

        public void UpdateRecordCount(int recordCountForAdd)
        {
            if (TaskParams.UpdateSessionDelegate != null)
                lock (Locker)
                    TaskParams.UpdateSessionDelegate(TaskParams.SessionId, recordCountForAdd, 0, 0, DM4Consts.SessionRun, false, true, false, false, SysUtils.GetTraffic(Rpm.SessionName), (StartTime - DateTime.Now).Ticks + PrevWorkTime);
        }

        /// <summary>
        /// writing to error and session log 
        /// </summary>
        public void WriteErrorLog(string message)
        {
            //DMN_Log
            Core.WriteLog(LogType.General, Rpm.SessionName, UsrId, message, MessageType.Error, ModuleCode);
            Core.WriteLog(LogType.Error, Rpm.SessionName, UsrId, message, MessageType.Error, ModuleCode);
            
            if (TaskParams.UpdateSessionDelegate != null)
                lock (Locker)
                    TaskParams.UpdateSessionDelegate(TaskParams.SessionId, 0, 1, 0, DM4Consts.SessionRun, false, false, false, true, SysUtils.GetTraffic(Rpm.SessionName), (StartTime - DateTime.Now).Ticks + PrevWorkTime);
        }

        public void WriteTestLog(string message, MessageType type = MessageType.Info)
        {
            //DMN_Log
            Core.WriteLog(LogType.Test, Rpm.SessionName, UsrId, message, type, ModuleCode);
            if (type == MessageType.Error)
                Core.WriteLog(LogType.Error, Rpm.SessionName, UsrId, message, type, ModuleCode);

        }

        public void WriteLog(string message, MessageType type = MessageType.Info)
        {
            //DMN_Log
            Core.WriteLog(LogType.General, Rpm.SessionName, UsrId, message, type, ModuleCode);
            if (type == MessageType.Error)
                Core.WriteLog(LogType.Error, Rpm.SessionName, UsrId, message, type, ModuleCode);
        }
    }
}

